package com.onpositive.wiki3.db.catmodel.matches.classify;

import java.io.IOException;
import java.util.HashSet;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.onpositive.nlp.inflector.SimplePOFParser;
import com.onpositive.nlp.inflector.StringLevenshteinDisstanceComputer;
import com.onpositive.wiki3.db.catmodel.Categories;
import com.onpositive.wiki3.db.catmodel.Category;
import com.onpositive.wiki3.db.catmodel.matches.MultiLevelMatcher;
import com.onpositive.wiki3.db.catmodel.matches.SelfLinksRemover;

public class ByMatcher extends AbstractRecordingMatcher {

	String[] title;
	HashSet<String> types = new HashSet<String>();

	HashSet<String> inheritancePrefixes = new HashSet<String>();

	// public static final String BY_TYPE = "by_type";
	// public static final String BY_COUNTRY = "by_country";
	// public static final String BY_PURPOSE = "by_purpose";
	// public static final String BY_MEDIA = "by_media";
	// public static final String BY_PLACE = "by_place";

	// _by_purpose

	public ByMatcher(RelationStore store) {
		super(store);
		try {
			Document parse = DocumentBuilderFactory.newInstance()
					.newDocumentBuilder()
					.parse(ByMatcher.class.getResourceAsStream("by_terms.xml"));
			NodeList elementsByTagName = parse.getElementsByTagName("term");
			title = new String[elementsByTagName.getLength()];
			for (int a = 0; a < elementsByTagName.getLength(); a++) {
				Element element = (Element) elementsByTagName.item(a);
				title[a] = "_by_" + element.getAttribute("name");
				if (element.getAttribute("subType").equals("true")) {
					types.add(title[a]);
				}
			}
			elementsByTagName = parse.getElementsByTagName("prefix");
			for (int a = 0; a < elementsByTagName.getLength(); a++) {
				Element element = (Element) elementsByTagName.item(a);
				inheritancePrefixes.add(element.getAttribute("name"));

			}
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public int accept(Category st) {
		boolean mark = false;
		if (st.toString().equals("automobiles_by_country")) {
			System.out.println("A");
		}
		String string = st.toString();
		String ts = null;
		for (String s : title) {
			if (string.endsWith(s)) {
				mark = true;
				ts = s;
				break;
			}
		}

		if (mark) {

			Category[] childCategories = st.getChildCategories();
			Category parent = findAcceptableParent(st, ts);
			if (parent != null) {
				for (Category cq : childCategories) {
					doRecord(ts, parent, cq, 0);
				}
			}
			mark(RelationConstants.GARBAGE, st);
			// if (parent == null) {
			// System.out.println(st);
			// }
		} else {
			String mmm = st.toString();
			String[] split = mmm.split("_");
			if (split.length > 2) {
				for (Category c : st.getChildCategories()) {
					String string2 = c.toString();
					// String[] split2 = string2.split("_");
					// for (String m:split2){
					// if (m.equals(st))
					// }
					if (string2.contains(st.toString())) {
						// FIX ME
						record(RelationConstants.IS_A, st, c);
					}
				}
			} else {
				for (Category c : st.getChildCategories()) {
					String string2 = c.toString();
					if (string2.equals("commercial_vehicles")) {
						System.out.println("a");
					}
					String[] split2 = string2.split("_");
					String core = SimplePOFParser.getCore(string2);
					String core1 = SimplePOFParser.getCore(st.toString());
					if (core.equals(core1)) {
						record(RelationConstants.IS_A, st, c);
						record(RelationConstants.TYPE_OF, st, c);
					}
					if (split2.length == 2) {
						if (inheritancePrefixes.contains(split2[0])) {
							if (split2[1].equals(mmm)) {
								record(RelationConstants.IS_A, st, c);
								record(RelationConstants.TYPE_OF, st, c);
							}
						}
					}

				}
			}

			if (!st.toString().endsWith("lists")) {
				for (Category cm : st.getChildCategories()) {
					String string2 = cm.toString();
					if (string2.startsWith("lists_of_")) {

						String substring = string2.substring("lists_of_"
								.length());
						if (doCompute(substring, st) < 10) {
							mark(RelationConstants.IS_A, st);
						}
					}
				}
			}

		}
		return 0;
	}

	protected Category findAcceptableParent(Category st, String ts) {
		String string = st.toString();

		Category[] parentsCategories = st.getParentsCategories();
		Category parent = simpleFind(string, parentsCategories);
		if (parentsCategories.length == 1) {
			parent = parentsCategories[0];
		}
		if (parent == null) {
			parent = tryFindInParents(string, ts, parentsCategories, parent);
		}
		if (parent == null) {
			parent = tryFindByName(st, string, ts, parent);

		}
		if (parent == null) {
			String substring = string.substring(0,
					string.length() - ts.length());
			for (Category c : parentsCategories) {
				int computeSmartDisstance = doCompute(substring, c);
				if (computeSmartDisstance <= 10) {
					parent = c;
				}
			}
		}
		return parent;
	}

	static final int MAX_LEVEL = 4;

	protected void doRecord(String ts, Category parent, Category cq, int level) {
		if (level > MAX_LEVEL) {
			return;
		}
		String string = cq.toString();
		if (isNotR(ts, parent)) {
			return;
		}
		if (isSubclassification(parent.toString())) {
			boolean endsWith = isType(parent);
			if (endsWith) {
				Category findAcceptableParent = findAcceptableParent(parent, ts);
				if (findAcceptableParent != null) {
					mark(RelationConstants.GARBAGE, cq);
					mark(RelationConstants.GARBAGE, parent);
					System.out.println(findAcceptableParent + "->" + cq);
					doRecord(ts, findAcceptableParent, cq, level + 1);
					return;
				}
			}
		}

		boolean isSubclassificationCat = isSubclassification(string);

		if (isSubclassificationCat) {
			for (Category c : cq.getChildCategories()) {
				doRecord(RelationConstants.IS_A, parent, c, level + 1);
			}
			mark(RelationConstants.GARBAGE, cq);
			return;
		}

		record(RelationConstants.IS_A, parent, cq);
		if (isType(ts)) {
			record(RelationConstants.TYPE_OF, parent, cq);
		}
	}

	protected boolean isType(Category parent) {
		String pm = parent.toString();
		return isType(pm);
	}

	protected boolean isType(String pm) {
		for (String s : types) {
			if (pm.endsWith(s)) {
				return true;
			}
		}
		return false;
	}

	protected boolean isSubclassification(String string) {
		boolean isSubclassificationCat = false;
		for (String s : title) {
			if (string.contains(s)) {
				isSubclassificationCat = true;
			}
		}
		return isSubclassificationCat;
	}

	private boolean isNotR(String ts, Category parent) {
		if (!isType(ts)) {
			if (ts.startsWith("years") || parent.toString().startsWith("years")) {
				return true;
			}
			String string = ts.toString();
			int indexOf = string.indexOf('_');
			if (indexOf != -1) {
				string = string.substring(0, indexOf);
				if (string.length() == 0) {
					return false;
				}
				if (Character.isDigit(string.charAt(0))) {
					return true;
				}
			}
		}
		return false;
	}

	protected int doCompute(String substring, Category c) {
		int computeSmartDisstance = StringLevenshteinDisstanceComputer
				.computeSmartDisstance(substring, c.toString());
		String replace = purify(substring);
		String sm1 = purify(c.toString());
		return Math.min(computeSmartDisstance,
				StringLevenshteinDisstanceComputer.computeSmartDisstance(
						replace, sm1));
	}

	protected String purify(String substring) {
		String replaceAll = substring.replaceAll("\\(.*\\)", "");
		String replace = replaceAll.replace("_", "");
		return replace;
	}

	protected Category simpleFind(String string, Category[] parentsCategories) {
		Category parent = null;
		for (Category m : parentsCategories) {
			String string2 = m.toString();
			if (string.contains(string2)) {
				// okey this is parent;
				if (parent != null) {
					if (!isType(parent)) {
						continue;
					}
				}
				parent = m;
				// break;
			}
		}
		return parent;
	}

	protected Category tryFindInParents(String string, String ts,
			Category[] parentsCategories, Category parent) {
		l2: for (Category m : parentsCategories) {
			String string2 = m.toString();
			if (string2.endsWith(ts)) {
				Category[] parentsCategories2 = m.getParentsCategories();
				for (Category c : parentsCategories2) {
					String z = c.toString();
					if (string.contains(z)) {
						// okey this is parent;
						parent = m;
						break l2;
					}
				}
			}

		}
		return parent;
	}

	protected Category tryFindByName(Category st, String string, String ts,
			Category parent) {
		String substring = string.substring(0, string.length() - ts.length());
		Categories store = st.getStore();
		Category category = store.get(substring);
		if (category != null) {
			parent = category;
		}
		if (substring.endsWith("s")) {
			substring = substring.substring(0, substring.length() - 1);
			category = store.get(substring);
			if (category != null) {
				parent = category;
			}
		} else {
			substring = substring + "s";
			category = store.get(substring);
			if (category != null) {
				parent = category;
			}
		}
		return parent;
	}

	public void close(Categories cm) {

		Categories categories = toRecord.get(RelationConstants.IS_A);
		categories.removeAllContaining(categories.getDb(), "lists_of");
		for (Category m : categories) {

			if (m.parentCount() <=1) {				
				Category category = cm.get(m.id());

				if (category != null) {
					int[] parents = category.getParents();
					for (int q : parents) {
						Category category2 = categories.get(q);

						Category pc = cm.get(q);
						if (pc.distance() > category.distance()
								|| category.distance() > 3) {
							if (category2 != null) {
								doRecord(RelationConstants.IS_A, category2, m,
										0);
							}
						}
					}
				}
			}
		}
		categories.accept(new MultiLevelMatcher(2));
		categories.accept(new SelfLinksRemover());
		for (Category m : categories) {
			if (m.deepSize() == -1) {
				System.out.println("Cycles");
				throw new IllegalStateException();
			}
		}
		categories = toRecord.get(RelationConstants.TYPE_OF);
		categories.accept(new MultiLevelMatcher(2));
		categories.accept(new SelfLinksRemover());

	}
}
